#include "cameraeth0.h"
#include "configmanager.h"
#include "errordialogmanager.h"
#include "modelstatusmanager.h"
#include "popupmanager.h"
#include "qtconcurrentrun.h"

CameraEth0 &CameraEth0::getInstance()
{
    static CameraEth0 instance;
    return instance;
}

CameraEth0::CameraEth0(QObject *parent) : Camera(parent),
    m_exposureTime(ParamValue.getParameter<float>("camera", "exposureTime")),
    m_exposureAuto(), m_gain(ParamValue.getParameter<float>("camera", "gain")),
    m_gainAuto(ParamValue.getParameter<int>("camera", "gainAuto")),
    m_balanceRatio(ParamValue.getParameter<float>("camera", "balanceRatio")),
    m_balanceAuto(ParamValue.getParameter<int>("camera", "balanceWhiteAuto")),
    m_cameraImgRoi(ParamValue.getParameter<QVariantList>("camera", "cameraRoi")),
    cameraVertical_(ParamValue.getParameter<bool>("camera", "cameraVertical")),
    cameraHorizontal_(ParamValue.getParameter<bool>("camera", "cameraHorizontal")),
    currentStatus(Closed),
    m_pcMyCamera(nullptr),
    isOpened(false)
{

    m_cameraInfo = QString("相机未连接");
    m_cameraInfoDetal["name"] = "空";
    m_cameraInfoDetal["MaxROI_wid"] = 3072;
    m_cameraInfoDetal["MaxROI_hei"] = 2048;
    m_cameraInfoDetal["DeviceType"] = "空";
    m_cameraInfoDetal["type"] = "空";

    connect(&ConfigManager::getInstance(), &ConfigManager::valueTableLoad, this, &CameraEth0::valueTableLoad);

    // emit cameraSourceImgSizeChanged();
}

CameraEth0::~CameraEth0()
{
    capRelease();
}

void CameraEth0::setExposureTime(float exposure)
{
    if (m_exposureTime != exposure)
    {
        if (exposure == 0)
        {
            LogWarning << "Failed to set exposure time to " << exposure;
            return;
        }
        m_exposureTime = exposure;
        LogDebug << "Attempting to set exposure time to " << exposure;
        {
            setExposureMode(0);
            std::lock_guard<std::mutex> lock(mtx);
            if (m_pcMyCamera == nullptr)
            {
                LogWarning << "Camera handle is null";
                return;
            }
            int nRet = m_pcMyCamera->SetFloatValue("ExposureTime", exposure);
            if (MV_OK != nRet)
            {
                LogError << "Failed to set exposure time: " << nRet;
            }
            else
            {
                LogInfo << "Exposure time set to " << exposure;
            }
        }
        ParamValue.setParameter("camera", "exposureTime", exposure);
        emit exposureTimeChanged();
    }
}

void CameraEth0::setExposureMode(int mode)
{
    LogDebug << "Attempting to set exposure mode to " << mode;
    {
        m_exposureAuto = mode;
        std::lock_guard<std::mutex> lock(mtx);
        if (m_pcMyCamera == nullptr)
        {
            LogWarning << "Camera handle is null";
            return;
        }
        int nRet = m_pcMyCamera->SetEnumValue("ExposureAuto", mode);
        if (MV_OK != nRet)
        {
            LogError << "Failed to set exposure mode: " << nRet;
        }
        else
        {
            LogInfo << "Exposure mode set to " << mode;
        }
    }
    ConfigManager::getInstance().setParameter("camera", "exposureAuto", mode);
    emit exposureAutoChanged();
}

void CameraEth0::setGain(float gain)
{
    if (m_gain != gain)
    {
        m_gain = gain;
        LogDebug << "Attempting to set gain to " << gain;
        {
            setGainAuto(0);
            std::lock_guard<std::mutex> lock(mtx);
            if (m_pcMyCamera == nullptr)
            {
                LogWarning << "Camera handle is null";
                return;
            }
            int nRet = m_pcMyCamera->SetFloatValue("Gain", gain);
            if (MV_OK != nRet)
            {
                LogError << "Failed to set gain: " << nRet;
            }
            else
            {
                LogInfo << "Gain set to " << gain;
            }
        }
        ParamValue.setParameter("camera", "gain", gain);
        emit gainChanged();
    }
}

void CameraEth0::setGainAuto(int mode)
{
    LogDebug << "Attempting to set gain auto mode to " << mode;
    {
        std::lock_guard<std::mutex> lock(mtx);
        if (m_pcMyCamera == nullptr)
        {
            LogWarning << "Camera handle is null";
            return;
        }

        int nRet = m_pcMyCamera->SetEnumValue("GainAuto", mode);
        if (MV_OK != nRet)
        {
            LogError << "Failed to set gain auto mode: " << nRet;
        }
        else
        {
            LogInfo << "Gain auto mode sbalanceWhiteAutoet to " << mode;
        }
    }
    m_gainAuto = mode;
    ConfigManager::getInstance().setParameter("camera", "gainAuto", mode);
    emit gainAutoChanged();
}

// void CameraEth0::setPixelFormat() {
//     int format;
//     LogDebug << "Attempting to set pixel format to " << format;
//     {
//         std::lock_guard<std::mutex> lock(mtx);
//         if (m_pcMyCamera == nullptr) {
//             LogWarning << "Camera handle is null";
//             return;
//         }

//         int nRet = m_pcMyCamera->SetEnumValue("PixelFormat", format);
//         if (MV_OK != nRet) {
//             LogError << "Failed to set pixel format: " << nRet;
//         } else {
//             LogInfo << "Pixel format set to " << format;
//         }
//     }
//     //ConfigManager::getInstance().setParameter("camera", "pixelFormat", format);
// }

void CameraEth0::setBalanceRatio(float ratio)
{
    if (m_balanceRatio != ratio)
    {
        m_balanceRatio = ratio;
        LogDebug << "Attempting to set balance ratio to " << ratio;
        {
            std::lock_guard<std::mutex> lock(mtx);
            if (m_pcMyCamera == nullptr)
            {
                LogWarning << "Camera handle is null";
                return;
            }
            // int nRet = m_pcMyCamera->balanceWhiteAutoSetFloatValue("BalanceRatio", ratio);
            // if (MV_OK != nRet) {
            //     LogError << "Failed to set balance ratio: " << nRet;
            // } else {
            //     LogInfo << "Balance ratio set to " << ratio;
            // }
        }
        ParamValue.setParameter("camera", "balanceRatio", ratio);
        emit balanceRatioChanged();
    }
}

void CameraEth0::setBalanceAuto(int mode)
{
    LogDebug << "Attempting to set balance auto mode to " << mode;
    {
        std::lock_guard<std::mutex> lock(mtx);
        if (m_pcMyCamera == nullptr)
        {
            LogWarning << "Camera handle is null";
            return;
        }
        m_balanceAuto = mode;
        int nRet = m_pcMyCamera->SetEnumValue("BalanceWhiteAuto", mode);
        if (MV_OK != nRet)
        {
            LogError << "Failed to set balance auto mode: " << nRet;
        }
        else
        {
            LogInfo << "Balance auto mode set to " << mode;
        }
    }
    ConfigManager::getInstance().setParameter("camera", "balanceWhiteAuto", mode);
    emit balanceAutoChanged();
}

void CameraEth0::setcameraHorizontal(bool mode)
{
    cameraHorizontal_ = mode;
    ParamValue.setParameter("camera", "cameraHorizontal", cameraHorizontal_);
    LogDebug << "setcameraHorizontal : " << cameraHorizontal_;
    emit cameraHorizontalChanged();
}

void CameraEth0::setcameraVertical(bool mode)
{
    cameraVertical_ = mode;
    ParamValue.setParameter("camera", "cameraVertical", cameraVertical_);
    LogDebug << "cameraVertical : " << cameraVertical_;
    emit cameraVerticalChanged();
}

void CameraEth0::updateCameraInfo()
{
    LogDebug << "Attempting to update camera";
    if (m_pcMyCamera == nullptr)
    {
        LogWarning << "Camera object is not initialized!";
        return;
    }

    MVCC_STRINGVALUE strValue;
    if (m_pcMyCamera->GetStringValue("DeviceModelName", &strValue) == MV_OK)
    {
        m_cameraInfoDetal["name"] = QString(strValue.chCurValue);
        LogDebug << "DeviceModelName" << QString(strValue.chCurValue);
    }
    else
    {
        m_cameraInfoDetal["name"] = "空";
        LogDebug << "Failed to get DeviceModelName";
    }

    MVCC_INTVALUE_EX intValue;
    if (m_pcMyCamera->GetIntValue("WidthMax", &intValue) == MV_OK)
    {
        m_cameraInfoDetal["MaxROI_wid"] = static_cast<int>(intValue.nCurValue);
        LogDebug << "WidthMax" << intValue.nCurValue;
    }
    else
    {
        m_cameraInfoDetal["MaxROI_wid"] = 0;
        LogDebug << "Failed to get WidthMax";
    }

    if (m_pcMyCamera->GetIntValue("HeightMax", &intValue) == MV_OK)
    {
        m_cameraInfoDetal["MaxROI_hei"] = static_cast<int>(intValue.nCurValue);
        LogDebug << "HeightMax" << intValue.nCurValue;
    }
    else
    {
        m_cameraInfoDetal["MaxROI_hei"] = 0;
        LogDebug << "Failed to get HeightMax";
    }
    if (m_cameraInfoDetal["MaxROI_wid"].toInt() && m_cameraInfoDetal["MaxROI_hei"].toInt())
    {
        ParamValue.setParameter("camera", "cameraHorizontal", QVariantList({m_cameraInfoDetal["MaxROI_wid"].toInt(), m_cameraInfoDetal["MaxROI_hei"].toInt(), 3}));
    }

    MVCC_ENUMVALUE enumValue;
    if (m_pcMyCamera->GetEnumValue("DeviceType", &enumValue) == MV_OK)
    {
        switch (enumValue.nCurValue)
        {
        case 0:
            m_cameraInfoDetal["DeviceType"] = "Transmitter";
            break;
        case 1:
            m_cameraInfoDetal["DeviceType"] = "Receiver";
            break;
        case 2:
            m_cameraInfoDetal["DeviceType"] = "Transceiver";
            break;
        case 3:
            m_cameraInfoDetal["DeviceType"] = "Peripheral";
            break;
        default:
            m_cameraInfoDetal["DeviceType"] = "Unknown";
            break;
        }
        LogDebug << "DeviceType" << enumValue.nCurValue;
    }
    else
    {
        m_cameraInfoDetal["DeviceType"] = "Unknown";
        LogDebug << "Failed to get DeviceType";
    }

    emit cameraInfoDetalChanged();
    // MV_CC_DEVICE_INFO deviceInfo;
    // memset(&deviceInfo, 0, sizeof(MV_CC_DEVICE_INFO));
    // if (m_pcMyCamera->GetDeviceInfo(&deviceInfo) == MV_OK) {
    //     QString modelName = QString::fromUtf8(reinterpret_cast<char*>(deviceInfo.SpecialInfo.stUsb3VInfo.chModelName));
    //     QString serialNumber = QString::fromUtf8(reinterpret_cast<char*>(deviceInfo.SpecialInfo.stUsb3VInfo.chSerialNumber));
    //     m_cameraInfo = QString("Model: %1, Serial: %2").arg(modelName).arg(serialNumber);
    //     emit cameraInfoChanged();
    // } else {
    //     m_cameraInfo = QString("相机未连接");
    //     emit cameraInfoChanged();
    //     LogError << "Failed to get device information";
    // }
    // LogDebug << "updateCameraInfo" << m_cameraInfo;
}

void CameraEth0::configDataChanged(QString Category, QString key)
{
    if (Category == "camera")
    {
        if (key == "exposureTime")
        {
            setExposureTime(ParamValue.getParameter<float>("camera", "exposureTime"));
        }
        else if (key == "exposureAuto")
        {
            setExposureMode(ParamValue.getParameter<int>("camera", "exposureAuto"));
        }
        else if (key == "gain")
        {
            setGain(ParamValue.getParameter<float>("camera", "gain"));
        }
        else if (key == "gainAuto")
        {
            setGainAuto(ParamValue.getParameter<int>("camera", "gainAuto"));
        }
        else if (key == "balanceRatio")
        {
            setBalanceRatio(ParamValue.getParameter<float>("camera", "balanceRatio"));
        }
        else if (key == "balanceWhiteAuto")
        {
            setBalanceAuto(ParamValue.getParameter<int>("camera", "balanceWhiteAuto"));
        }
        else if (key == "cameraRoi")
        {
            // setCameraImgRoi(ParamValue.getParameter<QVariantList>("camera", "cameraRoi"));
        }
        else if (key == "cameraHorizontal")
        {
            setcameraHorizontal(ParamValue.getParameter<bool>("camera", "cameraHorizontal"));
        }
        else if (key == "camecameraVerticalraRoi")
        {
            setcameraVertical(ParamValue.getParameter<bool>("camera", "cameraVertical"));
        }
    }
}

void CameraEth0::openCameraUpdateParam()
{
    m_exposureTime = -1 ;
    m_gain = -1 ;
    m_balanceRatio = 1;
    setExposureTime(ParamValue.getParameter<float>("camera", "exposureTime"));
    setExposureMode(ParamValue.getParameter<int>("camera", "exposureAuto"));
    setGain(ParamValue.getParameter<float>("camera", "gain"));
    setGainAuto(ParamValue.getParameter<int>("camera", "gainAuto"));
    setBalanceRatio(ParamValue.getParameter<float>("camera", "balanceRatio"));
    setBalanceAuto(ParamValue.getParameter<int>("camera", "balanceWhiteAuto"));
    setcameraHorizontal(ParamValue.getParameter<bool>("camera", "cameraHorizontal"));
    setcameraVertical(ParamValue.getParameter<bool>("camera", "cameraVertical"));
}

QVariantList CameraEth0::getAndsetAdjustedCameraRoi()
{
    QVariantList roiList = ParamValue.getParameter<QVariantList>("camera", "cameraRoi");
    m_cameraImgRoi.clear();
    bool change = false;
    for (int i = 0; i < roiList.size(); ++i)
    {
        int value = roiList[i].toInt();
        if (value % 32 != 0)
        {
            // Adjust value to the nearest multiple of 32
            value = (value / 32) * 32;
            if (value % 32 != 0)
            {
                value += 32;
                change = true;
            }
        }
        m_cameraImgRoi << value;
    }
    if (change)
        ParamValue.setParameter("camera", "cameraRoi", m_cameraImgRoi);
    return m_cameraImgRoi;
}

void CameraEth0::valueTableLoad()
{
    LogDebug << "Attempting valueTableLoad CameraEth0!";
    if (m_pcMyCamera == nullptr)
    {

        QVariantList roiList = ParamValue.getParameter<QVariantList>("camera", "cameraRoi");
        qDebug() << "1 cameraRoi roiList" << roiList;
        m_cameraImgRoi.clear();
        m_cameraImgRoi << roiList[0].toInt() << roiList[1].toInt() << roiList[2].toInt() << roiList[3].toInt();
        emit cameraImgRoiChanged();

        m_exposureTime = ParamValue.getParameter<float>("camera", "exposureTime");
        emit exposureTimeChanged();

        m_exposureAuto = ParamValue.getParameter<int>("camera", "exposureAuto");
        emit exposureAutoChanged();

        m_gain = ParamValue.getParameter<float>("camera", "gain");
        emit gainChanged();

        m_gainAuto = ParamValue.getParameter<int>("camera", "gainAuto");
        emit gainAutoChanged();

        m_balanceRatio = ParamValue.getParameter<float>("camera", "balanceRatio");
        emit balanceRatioChanged();

        m_balanceAuto = ParamValue.getParameter<int>("camera", "balanceWhiteAuto");
        emit balanceAutoChanged();

        cameraVertical_ = ParamValue.getParameter<bool>("camera", "cameraHorizontal");
        emit cameraHorizontalChanged();

        cameraHorizontal_ = ParamValue.getParameter<bool>("camera", "cameraVertical");
        emit cameraVerticalChanged();

        return;
    }
    QVariantList roiList = ParamValue.getParameter<QVariantList>("camera", "cameraRoi");
    qDebug() << "cameraRoi roiList" << roiList;
    setROI(roiList[0].toInt(), roiList[1].toInt(), roiList[2].toInt(), roiList[3].toInt());
    setExposureTime(ParamValue.getParameter<float>("camera", "exposureTime"));
    setExposureMode(ParamValue.getParameter<int>("camera", "exposureAuto"));
    setGain(ParamValue.getParameter<float>("camera", "gain"));
    setGainAuto(ParamValue.getParameter<int>("camera", "gainAuto"));
    setBalanceRatio(ParamValue.getParameter<float>("camera", "balanceRatio"));
    setBalanceAuto(ParamValue.getParameter<int>("camera", "balanceWhiteAuto"));
    setcameraHorizontal(ParamValue.getParameter<bool>("camera", "cameraHorizontal"));
    setcameraVertical(ParamValue.getParameter<bool>("camera", "cameraVertical"));
}

void CameraEth0::checkAndAdjustRoi()
{
    int maxRoiWidth = m_cameraInfoDetal["MaxROI_wid"].toInt();
    int maxRoiHeight = m_cameraInfoDetal["MaxROI_hei"].toInt();

    if (maxRoiWidth != 0 && maxRoiHeight != 0)
    {
        bool adjusted = false;

        if (m_cameraImgRoi.size() >= 2)
        {
            if (m_cameraImgRoi[0].toInt() + m_cameraImgRoi[2].toInt() > maxRoiWidth)
            {
                adjusted = true;
            }
            if (m_cameraImgRoi[1].toInt() + m_cameraImgRoi[3].toInt() > maxRoiHeight)
            {
                adjusted = true;
            }
        }

        if (adjusted)
        {
            LogDebug << "ROI adjusted to fit within max resolution";
            m_cameraImgRoi.clear();
            m_cameraImgRoi << 0 << 0 << maxRoiWidth << maxRoiHeight;
            // emit cameraImgRoiChanged();
            // PARAM.setCameraRoi({0,0,maxRoiWidth,maxRoiHeight});
            // Assuming there's a method to set m_cameraRoi in ParameterModel
            // m_parameterModel->setCameraRoi(roi);
        }
    }
}

void CameraEth0::setROI(int x, int y, int width, int height)
{
    {
        std::lock_guard<std::mutex> lock(mtx);
        if (m_pcMyCamera == nullptr)
        {
            LogWarning << "Camera handle is null";
            return;
        }

        width = (((int)(width / 32)) + 1) * 32;
        height = (((int)(height / 32)) + 1) * 32;
        x = (((int)(x / 32))) * 32;
        y = (((int)(y / 32))) * 32;

        int nRet = m_pcMyCamera->SetIntValue("Width", width);
        if (MV_OK != nRet)
        {
            LogError << "Failed to set Width mode: " << nRet;
        }
        nRet = m_pcMyCamera->SetIntValue("Height", height);
        if (MV_OK != nRet)
        {
            LogError << "Failed to set Height mode: " << nRet;
        }
        nRet = m_pcMyCamera->SetIntValue("OffsetX", x);
        if (MV_OK != nRet)
        {
            LogError << "Failed to set OffsetX mode: " << nRet;
        }
        nRet = m_pcMyCamera->SetIntValue("OffsetY", y);
        if (MV_OK != nRet)
        {
            LogError << "Failed to set OffsetY mode: " << nRet;
        }

        LogInfo << "ROI set to (" << x << ", " << y << ", " << width << ", " << height << ")";

        m_cameraImgRoi.clear();
        m_cameraImgRoi << x << y << width << height;
        ParamValue.setParameter("camera", "cameraRoi", m_cameraImgRoi);
        emit cameraImgRoiChanged();
        emit cameraSetOver();
    }
    restartCamera();
}

void CameraEth0::readGain()
{
    std::lock_guard<std::mutex> lock(mtx); // 加锁
    if (m_pcMyCamera == nullptr)
    {
        return;
    }

    MVCC_FLOATVALUE stFloatValue;
    int nRet = m_pcMyCamera->GetFloatValue("Gain", &stFloatValue);
    if (MV_OK != nRet)
    {
        LogError << "Failed to get gain: " << nRet;
        return;
    }

    float m_gain_ = static_cast<float>(stFloatValue.fCurValue);
    if (m_gain_ != m_gain)
    {
        m_gain = m_gain_;
        emit gainChanged();
    }
}

void CameraEth0::readBalanceRatio()
{
    std::lock_guard<std::mutex> lock(mtx); // 加锁
    if (m_pcMyCamera == nullptr)
    {
        return;
    }

    MVCC_INTVALUE_EX stFloatValue;
    int nRet = m_pcMyCamera->GetIntValue("BalanceRatio", &stFloatValue);
    if (MV_OK != nRet)
    {
        LogError << "Failed to get balance ratio: " << nRet;
        return;
    }

    float m_balanceRatio_ = static_cast<float>(stFloatValue.nCurValue);
    if (m_balanceRatio != m_balanceRatio_)
    {
        m_balanceRatio = m_balanceRatio_;
        emit balanceRatioChanged();
    }
}

void CameraEth0::readImageCompressionMode()
{
    std::lock_guard<std::mutex> lock(mtx); // 加锁
    if (m_pcMyCamera == nullptr)
    {
        return;
    }

    MVCC_ENUMVALUE stEnumValue;
    int nRet = m_pcMyCamera->GetEnumValue("ImageCompressionMode", &stEnumValue);
    if (MV_OK != nRet)
    {
        LogError << "Failed to get image compression mode: " << nRet;
        return;
    }

    QString newImageCompressionMode;
    switch (stEnumValue.nCurValue)
    {
    case 0:
        newImageCompressionMode = "关闭";
        break;
    case 1:
        newImageCompressionMode = "JPEG";
        break;
    default:
        newImageCompressionMode = "未知";
        break;
    }

    if (m_imageCompressionMode != newImageCompressionMode)
    {
        m_imageCompressionMode = newImageCompressionMode;
        // emit imageCompressionModeChanged();
    }
}

void CameraEth0::readExposureTime()
{
    std::lock_guard<std::mutex> lock(mtx); // 加锁
    if (m_pcMyCamera == nullptr)
    {
        return;
    }

    MVCC_FLOATVALUE stFloatValue;
    int nRet = m_pcMyCamera->GetFloatValue("ExposureTime", &stFloatValue);
    if (MV_OK != nRet)
    {
        LogError << "Failed to get exposure time: " << nRet;
        return;
    }

    float newExposureTime = static_cast<float>(stFloatValue.fCurValue);
    if (newExposureTime != m_exposureTime)
    {
        m_exposureTime = newExposureTime;
        emit exposureTimeChanged();
    }
}

void CameraEth0::readDeviceMaxThroughput()
{
    MVCC_INTVALUE_EX stIntValue;
    {

        if (m_pcMyCamera == nullptr)
        {
            return;
        }
        std::lock_guard<std::mutex> lock(mtx); // 加锁
        int nRet = m_pcMyCamera->GetIntValue("DeviceMaxThroughput", &stIntValue);
        if (MV_OK != nRet)
        {
            LogError << "Failed to get device max throughput: " << nRet;
            return;
        }
    }
    int newDeviceMaxThroughput = static_cast<int>(stIntValue.nCurValue);
    if (m_deviceMaxThroughput != newDeviceMaxThroughput)
    {
        m_deviceMaxThroughput = newDeviceMaxThroughput;
        emit deviceMaxThroughputChanged();
    }
}

void CameraEth0::monitorParameters()
{

    if (ModelStatusManager::instance().getCameraStatus() == Running)
    {
        readGain();
        readBalanceRatio();
        // readImageCompressionMode();
        readExposureTime();
        readDeviceMaxThroughput();
    }
}

float CameraEth0::getFrameRate()
{
    std::lock_guard<std::mutex> lock(mtx); // 加锁
    if (m_pcMyCamera == nullptr)
    {
        LogWarning << "Camera handle is null";
        return 0.0f;
    }

    MVCC_FLOATVALUE stFloatValue;
    int nRet = m_pcMyCamera->GetFloatValue("ResultingFrameRate", &stFloatValue);
    if (MV_OK != nRet)
    {
        LogError << "Failed to get frame rate: " << nRet;
        return 0.0f;
    }

    return stFloatValue.fCurValue;
}

int CameraEth0::getThroughput()
{
    std::lock_guard<std::mutex> lock(mtx); // 加锁
    if (m_pcMyCamera == nullptr)
    {
        LogWarning << "Camera handle is null";
        return 0;
    }

    MVCC_INTVALUE_EX stIntValue;
    int nRet = m_pcMyCamera->GetIntValue("DeviceMaxThroughput", &stIntValue);
    if (MV_OK != nRet)
    {
        LogError << "Failed to get device throughput: " << nRet;
        return 0;
    }

    return static_cast<int>(stIntValue.nCurValue);
}

bool CameraEth0::getIsOpened()
{
    return isOpened;
}

void CameraEth0::capRelease()
{
    std::lock_guard<std::mutex> lock(mtx);
    ModelStatusManager::instance().setCameraStatus(CameraEth0::Closed);
    currentStatus = Closed;
    LogInfo << "Camera released";
    if (m_pcMyCamera && m_pcMyCamera->IsDeviceConnected())
    {
        LogInfo << "Camera in released";
        m_pcMyCamera->Close();
        delete m_pcMyCamera;
        m_pcMyCamera = nullptr;
    }
    m_pcMyCamera = nullptr;
    isOpened = false;
    LogInfo << "Camera released finish";
}

cv::Mat CameraEth0::getImage()
{
    LogTrack << "Attempting to get image";

    if (m_pcMyCamera == nullptr) {
        LogWarning << "Camera handle is null";
        return cv::Mat();
    }
    std::lock_guard<std::mutex> lock(mtx);
    if (m_pcMyCamera == nullptr) {
        LogWarning << "getImage m_pcMyCamera is null after locking";
        return cv::Mat();
    }
    MV_FRAME_OUT stFrameOut = {0};

    int nRet = m_pcMyCamera->CommandExecute("TriggerSoftware");
    if(MV_OK != nRet)
    {
        LogError << "TriggerSoftware fail! nRet :" << nRet;
        return cv::Mat();
    }

     nRet = m_pcMyCamera->GetImageBuffer(&stFrameOut, 1000);
    if (MV_OK != nRet) {
        LogError << "Failed to get image buffer: " << nRet;
        // ModelStatusManager::instance().setError("Camera", "Failed to get image buffer");
        // ModelStatusManager::instance().setCameraStatus(Error);
        return cv::Mat();
    }
    if (stFrameOut.stFrameInfo.enPixelType != PixelType_Gvsp_BayerRG8) {
        LogWarning << "Unsupported pixel format: " << stFrameOut.stFrameInfo.enPixelType;
        m_pcMyCamera->FreeImageBuffer(&stFrameOut);
        return cv::Mat();
    }

    // Create a temporary cv::Mat with the Bayer data
    cv::Mat imageTemp(stFrameOut.stFrameInfo.nHeight, stFrameOut.stFrameInfo.nWidth, CV_8UC1, stFrameOut.pBufAddr);

    // Check if imageTemp is empty
    if (imageTemp.empty()) {
        LogError << "Temporary image is empty after creation";
        m_pcMyCamera->FreeImageBuffer(&stFrameOut);
        return cv::Mat();
    }

    // Convert the Bayer image to a BGR image
    cv::Mat image;
    cv::cvtColor(imageTemp, image, cv::COLOR_BayerBG2BGR);

    if (image.empty()) {
        LogError << "Converted image is empty after cvtColor";
        m_pcMyCamera->FreeImageBuffer(&stFrameOut);
        return cv::Mat();
    }

    // Free the image buffer after processing
    m_pcMyCamera->FreeImageBuffer(&stFrameOut);

    if (cameraHorizontal_) {
        cv::flip(image, image, 1); // Horizontal flip
    }
    if (cameraVertical_) {
        cv::flip(image, image, 0); // Vertical flip
    }

    return image;
}


void CameraEth0::getCameraInfo(MV_CC_DEVICE_INFO *pDeviceInfo)
{

    // if (NULL == pDeviceInfo)
    // {
    //     return;
    // }
    // char strUserName[256] = {0};
    // if (pDeviceInfo->nTLayerType == MV_GIGE_DEVICE)
    // {
    //     int nIp1 = ((pDeviceInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
    //     int nIp2 = ((pDeviceInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
    //     int nIp3 = ((pDeviceInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
    //     int nIp4 = (pDeviceInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);

    //     if (strcmp("", (char*)pDeviceInfo->SpecialInfo.stGigEInfo.chUserDefinedName) != 0)
    //     {
    //         snprintf(strUserName, 256, "[%d]GigE:   %s (%s) (%d.%d.%d.%d)", 0, pDeviceInfo->SpecialInfo.stGigEInfo.chUserDefinedName,
    //                  pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber, nIp1, nIp2, nIp3, nIp4);
    //     }
    //     else
    //     {
    //         snprintf(strUserName, 256, "[%d]GigE:   %s (%s) (%d.%d.%d.%d)", 0, pDeviceInfo->SpecialInfo.stGigEInfo.chModelName,
    //                  pDeviceInfo->SpecialInfo.stGigEInfo.chSerialNumber, nIp1, nIp2, nIp3, nIp4);
    //     }
    // }
    // else if (pDeviceInfo->nTLayerType == MV_USB_DEVICE)
    // {
    //     if (strcmp("", (char*)pDeviceInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName) != 0)
    //     {
    //         snprintf(strUserName, 256, "[%d]UsbV3:  %s (%s)", 0, pDeviceInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName,
    //                  pDeviceInfo->SpecialInfo.stUsb3VInfo.chSerialNumber);
    //     }
    //     else
    //     {

    //         snprintf(strUserName, 256, "[%d]UsbV3:  %s (%s)", 0, pDeviceInfo->SpecialInfo.stUsb3VInfo.chModelName,
    //                  pDeviceInfo->SpecialInfo.stUsb3VInfo.chSerialNumber);
    //     }
    // }
    // else
    // {
    //     LogError << "Unknown device enumerated";
    // }
    // emit cameraInfoDetalChanged();
}

void CameraEth0::capOpen()
{
    ModelStatusManager::instance().setCameraStatus(CameraEth0::Closed);
    QtConcurrent::run(
        [this]()
        {
            LogInfo << "Attempting  Open Camera ...." ;
            {
                std::lock_guard<std::mutex> lock(mtx);
                PopupManager::instance().showPopup("相机打开中", "正在打开相机中…………"); // 显示等待弹窗
                int ret ;
                if (isOpened) {
                    PopupManager::instance().hidePopup();
                    LogInfo << "camara has been Opened" ;
                    return;
                }

                if (m_pcMyCamera == nullptr) {
                    m_pcMyCamera = new CMvCamera();
                }

                MV_CC_DEVICE_INFO_LIST stDevList;
                MV_CC_DEVICE_INFO* pDeviceInfo ;

                memset(&stDevList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
                int nRet = CMvCamera::EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDevList);
                if (MV_OK != nRet || stDevList.nDeviceNum == 0) {
                    LogWarning << "No camera devices found";
                    ModelStatusManager::instance().setError("Camera", "No devices found");
                    ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
                    goto capOpenError;
                }
                qInfo() << "find camrera num :" << stDevList.nDeviceNum;
                pDeviceInfo = stDevList.pDeviceInfo[0];
                if (pDeviceInfo == nullptr) {
                    LogError << "Device info is null";
                    ModelStatusManager::instance().setError("Camera", "Device info is null");
                    ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
                    goto capOpenError;
                }
                qInfo() << "pDeviceInfo[0]:" << pDeviceInfo->nMajorVer;
                ret = m_pcMyCamera->Open(pDeviceInfo);
                if (ret != MV_OK) {
                    delete m_pcMyCamera;
                    m_pcMyCamera = nullptr;
                    LogError << "Failed to open camera: " << ret;
                    ModelStatusManager::instance().setError("Camera", "Failed to open camera");
                    ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
                    goto capOpenError;
                }

                if (stDevList.pDeviceInfo[0]->nTLayerType == MV_GIGE_DEVICE)
                {
                    m_cameraInfoDetal["type"] = "网口相机";
                    unsigned int nPacketSize = 0;
                    nRet = m_pcMyCamera->GetOptimalPacketSize(&nPacketSize);
                    if (nRet == MV_OK)
                    {
                        nRet = m_pcMyCamera->SetIntValue("GevSCPSPacketSize",nPacketSize);
                        if(nRet != MV_OK)
                        {
                            LogError << "Warning: Set Packet Size fail!" << nRet;
                        }
                    }
                    else
                    {
                        LogError << "Warning: Get Packet Size fail!" <<  nRet;
                    }
                }else if(stDevList.pDeviceInfo[0]->nTLayerType == MV_USB_DEVICE)
                {
                    m_cameraInfoDetal["type"] = "USB相机";
                }else
                {
                    m_cameraInfoDetal["type"] = "未知型号";
                }

                updateCameraInfo();
                checkAndAdjustRoi();
                ModelStatusManager::instance().setCameraStatus(CameraEth0::Opened);

                LogInfo << "roi" << m_cameraImgRoi[0].toInt() << "|" << m_cameraImgRoi[1].toInt()
                        << "|" << m_cameraImgRoi[2].toInt() << "|" << m_cameraImgRoi[3].toInt();

                ret = m_pcMyCamera->SetIntValue("OffsetX", 0);
                if (ret != MV_OK) {
                    LogError << "OffsetX " << ret;
                }

                ret = m_pcMyCamera->SetIntValue("OffsetY", 0);
                if (ret != MV_OK) {
                    LogError << "OffsetY " << ret;
                }
                m_cameraImgRoi = getAndsetAdjustedCameraRoi();
                LogInfo << "roi" << m_cameraImgRoi[0].toInt() << "|" << m_cameraImgRoi[1].toInt()
                        << "|" << m_cameraImgRoi[2].toInt() << "|" << m_cameraImgRoi[3].toInt();
                ret = m_pcMyCamera->SetIntValue("Height", static_cast<unsigned int>(m_cameraImgRoi[3].toInt()));
                if (ret != MV_OK) {
                    LogError << "Height " << ret;
                }

                ret = m_pcMyCamera->SetIntValue("Width", static_cast<unsigned int>(m_cameraImgRoi[2].toInt()));
                if (ret != MV_OK) {
                    LogError << "Width " << ret;
                }

                ret = m_pcMyCamera->SetIntValue("OffsetX", static_cast<unsigned int>(m_cameraImgRoi[0].toInt()));
                if (ret != MV_OK) {
                    LogError << "OffsetX " << ret;
                }

                ret = m_pcMyCamera->SetIntValue("OffsetY", static_cast<unsigned int>(m_cameraImgRoi[1].toInt()));
                if (ret != MV_OK) {
                    LogError << "OffsetY " << ret;
                }


                ret = m_pcMyCamera->SetImageNodeNum(1);
                if (ret != MV_OK) {
                    LogError << "SetImageNodeNum " << ret;
                } else {
                    LogInfo << "SetImageNodeNum" << 1;
                }

                ret = m_pcMyCamera->SetEnumValue("PixelFormat", PixelType_Gvsp_BayerRG8);
                if (ret != MV_OK) {
                    LogError << "Failed to set pixel format: " << ret;
                } else {
                    LogInfo << "Pixel format set to " << PixelType_Gvsp_BayerRG8;
                }


                // 设置触发模式为on
                // set trigger mode as on
                nRet = m_pcMyCamera->SetEnumValue( "TriggerMode", 1);
                if (MV_OK != nRet)
                {
                    LogError << "MV_CC_SetTriggerMode fail! nRet:" << nRet;
                }
                // 设置触发源
                // set trigger source
                nRet = m_pcMyCamera->SetEnumValue( "TriggerSource", MV_TRIGGER_SOURCE_SOFTWARE);
                if (MV_OK != nRet)
                {
                    LogError << "MV_CC_SetTriggerSource fail! nRet :" << nRet;
                }



                ret = m_pcMyCamera->StartGrabbing();
                if (ret != MV_OK) {
                    LogError << "Start grabbing fail: " << ret;
                    ModelStatusManager::instance().setError("Camera", "Failed to start grabbing");
                    ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
                    goto capOpenError;
                }
            }
            openCameraUpdateParam();
            isOpened = true;
            currentStatus = CameraEth0::Running;
            LogInfo << "Camera opened successfully";
            ModelStatusManager::instance().setCameraStatus(CameraEth0::Running);
            PopupManager::instance().hidePopup();
            isOpened = true;

            setStatus(Idle);
            emit isOpenedChanged();
            return;
        capOpenError:
            ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
            ErrorDialogManager::instance().showNonBlockingError("打开相机错误", "请尝试重新打开");
            isOpened = false;
            emit isOpenedChanged();
            PopupManager::instance().hidePopup();
            return; });
}

void CameraEth0::restartCamera()
{
    // ErrorDialogManager::instance().showNonBlockingError("打开相机错误", "请尝试重新打开");
    QtConcurrent::run([this]()
                      {
                          PopupManager::instance().showPopup("相机重启中", "正在重启相机中…………"); // 显示等待弹窗
                          capRelease();
                          capOpen();
                          PopupManager::instance().hideAllPopups(); });
    // ModelStatusManager::instance().setCameraStatus(CameraEth0::Paused);
    // QtConcurrent::run([this]() {
    //     std::lock_guard<std::mutex> lock(mtx);
    //     PopupManager::instance().showPopup("相机重启中", "正在重启相机中…………"); // 显示等待弹窗

    //     updateCameraInfo();
    //     if (m_pcMyCamera && m_pcMyCamera->IsDeviceConnected()) {
    //         int ret = m_pcMyCamera->CommandExecute("Device");
    //         if (ret != MV_OK) {
    //             LogError << "Failed to  camera: " << ret;
    //             ModelStatusManager::instance().setError("Camera", "Failed to  camera");
    //             ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
    //             PopupManager::instance().hidePopup();
    //             return;
    //         }
    //         QThread::msleep(2000);
    //         // 轮询等待设备重启完成
    //         int attempts = 50; // 尝试次数，每次等待100ms，总共5秒
    //         while (attempts > 0) {
    //             QThread::msleep(100);
    //             if (m_pcMyCamera->IsDeviceConnected()) {
    //                 break;
    //             }
    //             attempts--;
    //         }

    //         if (!m_pcMyCamera->IsDeviceConnected()) {
    //             LogError << "Camera is not connected after ";
    //             ModelStatusManager::instance().setError("Camera", "Camera is not connected after ");
    //             ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
    //             PopupManager::instance().hidePopup();
    //             return;
    //         }

    //         // 更新设备信息
    //         updateCameraInfo();

    //         // 重新开始抓图
    //         ret = m_pcMyCamera->StartGrabbing();
    //         if (ret != MV_OK) {
    //             LogError << "Start grabbing fail after : " << ret;
    //             ModelStatusManager::instance().setError("Camera", "Failed to start grabbing after ");
    //             ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
    //             PopupManager::instance().hidePopup();
    //             return;
    //         }

    //         isOpened = true;
    //         currentStatus = CameraEth0::Running;
    //         LogInfo << "Camera restarted and running successfully";
    //         ModelStatusManager::instance().setCameraStatus(CameraEth0::Running);
    //         PopupManager::instance().hidePopup();
    //     } else {
    //         LogError << "Camera is not connected";
    //         ModelStatusManager::instance().setError("Camera", "Camera is not connected");
    //         ModelStatusManager::instance().setCameraStatus(CameraEth0::Error);
    //         PopupManager::instance().hidePopup();
    //     }
    // });
}

void CameraEth0::resetRoi()
{
    {
        if (!isOpened)
        {
            LogError << "Fail resetRoi isOpened = 0 ";
            ErrorDialogManager::instance().showNonBlockingError("重置失败", "请先打开相机");
        }

        m_cameraImgRoi.clear();
        m_cameraImgRoi << 0 << 0 << m_cameraInfoDetal["MaxROI_wid"].toInt() << m_cameraInfoDetal["MaxROI_hei"].toInt();
        ParamValue.setParameter("camera", "cameraRoi", m_cameraImgRoi);
        emit cameraImgRoiChanged();

        int maxRoiWidth = m_cameraInfoDetal["MaxROI_wid"].toInt();
        int maxRoiHeight = m_cameraInfoDetal["MaxROI_hei"].toInt();
        if (maxRoiWidth == 0 || maxRoiHeight == 0)
        {
            LogError << "Fail resetRoi maxRoiWidth == 0 || maxRoiHeight == 0";
            ErrorDialogManager::instance().showNonBlockingError("重置失败", "无法找到原始尺寸，请重启相机");
            return;
        }
        emit cameraResetOver();
        // std::lock_guard<std::mutex> lock(mtx);
        // int ret = m_pcMyCamera->SetIntValue("Width",  m_cameraRoi[2]);
        // if (ret != MV_OK) {
        //     LogError << "Width " << ret;
        // }
        // ret  = m_pcMyCamera->SetIntValue("Height", m_cameraRoi[3]);
        // if (ret != MV_OK) {
        //     LogError << "Height " << ret;
        // }
        // ret = m_pcMyCamera->SetIntValue("OffsetX", m_cameraRoi[0]);
        // if (ret != MV_OK) {
        //     LogError << "OffsetX " << ret;
        // }
        // ret =  m_pcMyCamera->SetIntValue("OffsetY", m_cameraRoi[1]);
        // if (ret != MV_OK) {
        //     LogError << "OffsetY " << ret;
        // }
        // ret  = m_pcMyCamera->SetEnumValue("RegionSelector", 8);
    }
    restartCamera();
}


//czh
void CameraEth0::photograph(){


}
